"""
优化功能API路由
提供文章分析和优化建议的RESTful接口
"""

from fastapi import APIRouter, HTTPException, Depends, WebSocket, WebSocketDisconnect, Request
from fastapi.responses import JSONResponse
from pydantic import BaseModel, Field
from typing import List, Optional, Dict, Any
from datetime import datetime
import json
import asyncio
import logging
from slowapi import Limiter
from slowapi.util import get_remote_address

from ..core.auth import get_current_user, User
from ..core.database import get_db, Database
from ..optimization import (
    OptimizationEngine,
    OptimizationType,
    OptimizationStatus
)

logger = logging.getLogger(__name__)

# 初始化速率限制器
limiter = Limiter(key_func=get_remote_address)

router = APIRouter(prefix="/api/v1/optimization", tags=["optimization"])

# 全局优化引擎实例，使用Redis URL（从环境变量获取）
import os
redis_url = os.getenv("REDIS_URL", "redis://localhost:6379/0")
optimization_engine = OptimizationEngine(redis_url=redis_url)

# WebSocket连接管理
class ConnectionManager:
    def __init__(self):
        self.active_connections: Dict[str, WebSocket] = {}
    
    async def connect(self, websocket: WebSocket, client_id: str):
        await websocket.accept()
        self.active_connections[client_id] = websocket
    
    def disconnect(self, client_id: str):
        if client_id in self.active_connections:
            del self.active_connections[client_id]
    
    async def send_message(self, message: str, client_id: str):
        if client_id in self.active_connections:
            await self.active_connections[client_id].send_text(message)
    
    async def broadcast(self, message: str):
        for connection in self.active_connections.values():
            await connection.send_text(message)

manager = ConnectionManager()


# 请求模型
class AnalysisRequest(BaseModel):
    """分析请求"""
    content: str = Field(..., description="文章内容")
    title: Optional[str] = Field(None, description="文章标题")
    optimization_types: Optional[List[str]] = Field(None, description="优化类型")
    keywords: Optional[List[str]] = Field(None, description="目标关键词")
    user_id: Optional[str] = Field(None, description="用户ID")
    article_id: Optional[str] = Field(None, description="文章ID")


class ApplyOptimizationRequest(BaseModel):
    """应用优化请求"""
    task_id: str = Field(..., description="任务ID")
    suggestion_id: str = Field(..., description="建议ID")
    content: str = Field(..., description="当前内容")
    custom_text: Optional[str] = Field(None, description="自定义替换文本")


class BatchOptimizationRequest(BaseModel):
    """批量优化请求"""
    task_id: str = Field(..., description="任务ID")
    suggestion_ids: List[str] = Field(..., description="建议ID列表")
    content: str = Field(..., description="当前内容")


class AutoOptimizeRequest(BaseModel):
    """自动优化请求"""
    content: str = Field(..., description="文章内容")
    apply_basic_rules: bool = Field(True, description="应用基本规则")


# 响应模型
class AnalysisResponse(BaseModel):
    """分析响应"""
    task_id: str
    status: str
    overall_score: float
    content_length: int
    created_at: str
    scores: Dict[str, Optional[float]]
    suggestions_count: int
    high_priority_count: int
    message: str


class SuggestionResponse(BaseModel):
    """建议响应"""
    id: str
    type: str
    priority: str
    description: str
    detail: str
    location: Optional[str]
    original_text: Optional[str]
    suggested_text: Optional[str]
    impact_score: float
    auto_applicable: bool
    applied: bool


class OptimizedContentResponse(BaseModel):
    """优化内容响应"""
    success: bool
    original_content: str
    optimized_content: str
    changes_count: int
    history: List[Dict[str, Any]]


@router.post("/analyze", response_model=AnalysisResponse)
@limiter.limit("10/minute")  # 每分钟最多10次请求
async def analyze_content(
    request: AnalysisRequest,
    req: Request,  # Required for limiter
    current_user: User = Depends(get_current_user),
    db: Database = Depends(get_db)
):
    """
    分析文章内容
    
    执行多维度内容分析，包括结构、连贯性、流畅度、关键词和标题优化
    Rate limit: 10 requests per minute
    """
    try:
        # 转换优化类型
        optimization_types = None
        if request.optimization_types:
            optimization_types = []
            for type_str in request.optimization_types:
                try:
                    opt_type = OptimizationType(type_str)
                    optimization_types.append(opt_type)
                except ValueError:
                    logger.warning(f"Invalid optimization type: {type_str}")
        
        # 执行分析
        analysis = await optimization_engine.analyze(
            content=request.content,
            title=request.title or "",
            optimization_types=optimization_types,
            keywords=request.keywords
        )
        
        # 保存到数据库
        if db:
            await db.optimization_tasks.insert_one({
                "task_id": analysis.task_id,
                "user_id": request.user_id or current_user.id,
                "article_id": request.article_id,
                "content": request.content[:1000],  # 只保存前1000字符
                "title": request.title,
                "analysis": optimization_engine.export_analysis(analysis.task_id),
                "status": analysis.status.value,
                "created_at": analysis.created_at,
                "updated_at": analysis.updated_at
            })
        
        # 构建响应
        export_data = optimization_engine.export_analysis(analysis.task_id)
        
        return AnalysisResponse(
            task_id=analysis.task_id,
            status=analysis.status.value,
            overall_score=analysis.overall_score,
            content_length=analysis.content_length,
            created_at=analysis.created_at.isoformat(),
            scores=export_data.get('scores', {}),
            suggestions_count=export_data.get('suggestions_count', 0),
            high_priority_count=export_data.get('high_priority_count', 0),
            message="分析完成"
        )
    
    except Exception as e:
        logger.error(f"Analysis failed: {str(e)}")
        raise HTTPException(status_code=500, detail=f"分析失败: {str(e)}")


@router.get("/{task_id}/suggestions", response_model=List[SuggestionResponse])
@limiter.limit("30/minute")  # 每分钟最多30次请求
async def get_suggestions(
    task_id: str,
    req: Request,  # Required for limiter
    limit: int = 20,
    priority: Optional[str] = None,
    current_user: User = Depends(get_current_user)
):
    """
    获取优化建议
    
    返回指定任务的优化建议列表，支持按优先级筛选
    """
    try:
        # 获取分析结果
        export_data = optimization_engine.export_analysis(task_id)
        if not export_data:
            raise HTTPException(status_code=404, detail="任务不存在")
        
        # 获取完整分析结果
        analysis = optimization_engine.analysis_cache.get(task_id)
        if not analysis:
            raise HTTPException(status_code=404, detail="分析结果不存在")
        
        # 筛选建议
        suggestions = analysis.prioritized_suggestions[:limit]
        
        if priority:
            suggestions = [s for s in suggestions if s.priority == priority]
        
        # 构建响应
        response = []
        for sug in suggestions:
            response.append(SuggestionResponse(
                id=sug.id,
                type=sug.type.value,
                priority=sug.priority,
                description=sug.description,
                detail=sug.detail,
                location=sug.location,
                original_text=sug.original_text,
                suggested_text=sug.suggested_text,
                impact_score=sug.impact_score,
                auto_applicable=sug.auto_applicable,
                applied=sug.applied
            ))
        
        return response
    
    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"Failed to get suggestions: {str(e)}")
        raise HTTPException(status_code=500, detail=f"获取建议失败: {str(e)}")


@router.post("/apply", response_model=OptimizedContentResponse)
@limiter.limit("20/minute")  # 每分钟最多20次请求
async def apply_optimization(
    request: ApplyOptimizationRequest,
    req: Request,  # Required for limiter
    current_user: User = Depends(get_current_user),
    db: Database = Depends(get_db)
):
    """
    应用单个优化建议
    
    将指定的优化建议应用到内容上
    """
    try:
        # 应用优化
        optimized_content, history = optimization_engine.apply_optimization(
            task_id=request.task_id,
            suggestion_id=request.suggestion_id,
            content=request.content,
            custom_text=request.custom_text
        )
        
        # 更新数据库
        if db:
            await db.optimization_tasks.update_one(
                {"task_id": request.task_id},
                {
                    "$push": {
                        "applied_suggestions": {
                            "suggestion_id": request.suggestion_id,
                            "applied_at": datetime.now(),
                            "custom_text": request.custom_text
                        }
                    },
                    "$set": {"updated_at": datetime.now()}
                }
            )
        
        return OptimizedContentResponse(
            success=True,
            original_content=request.content,
            optimized_content=optimized_content,
            changes_count=1,
            history=[{
                "suggestion_id": history.suggestion_id,
                "action": history.action,
                "timestamp": history.timestamp.isoformat()
            }]
        )
    
    except ValueError as e:
        raise HTTPException(status_code=404, detail=str(e))
    except Exception as e:
        logger.error(f"Failed to apply optimization: {str(e)}")
        raise HTTPException(status_code=500, detail=f"应用优化失败: {str(e)}")


@router.post("/batch-apply", response_model=OptimizedContentResponse)
async def batch_apply_optimizations(
    request: BatchOptimizationRequest,
    current_user: User = Depends(get_current_user)
):
    """
    批量应用优化建议
    
    一次应用多个优化建议
    """
    try:
        # 批量应用
        optimized_content, history_records = optimization_engine.batch_apply_optimizations(
            task_id=request.task_id,
            suggestion_ids=request.suggestion_ids,
            content=request.content
        )
        
        return OptimizedContentResponse(
            success=True,
            original_content=request.content,
            optimized_content=optimized_content,
            changes_count=len(history_records),
            history=[{
                "suggestion_id": h.suggestion_id,
                "action": h.action,
                "timestamp": h.timestamp.isoformat()
            } for h in history_records]
        )
    
    except Exception as e:
        logger.error(f"Failed to batch apply optimizations: {str(e)}")
        raise HTTPException(status_code=500, detail=f"批量应用失败: {str(e)}")


@router.post("/auto-optimize", response_model=OptimizedContentResponse)
async def auto_optimize_content(
    request: AutoOptimizeRequest,
    current_user: User = Depends(get_current_user)
):
    """
    自动优化内容
    
    应用基本的自动优化规则
    """
    try:
        if request.apply_basic_rules:
            optimized_content = optimization_engine.auto_optimize(request.content)
        else:
            optimized_content = request.content
        
        # 计算改变数量（简单估计）
        changes_count = sum([
            1 for i in range(min(len(request.content), len(optimized_content)))
            if i < len(request.content) and i < len(optimized_content) 
            and request.content[i] != optimized_content[i]
        ])
        
        return OptimizedContentResponse(
            success=True,
            original_content=request.content,
            optimized_content=optimized_content,
            changes_count=changes_count,
            history=[]
        )
    
    except Exception as e:
        logger.error(f"Auto optimization failed: {str(e)}")
        raise HTTPException(status_code=500, detail=f"自动优化失败: {str(e)}")


@router.post("/{task_id}/undo/{suggestion_id}")
async def undo_optimization(
    task_id: str,
    suggestion_id: str,
    current_user: User = Depends(get_current_user)
):
    """
    撤销优化
    
    撤销已应用的优化建议
    """
    try:
        success = optimization_engine.undo_optimization(task_id, suggestion_id)
        
        if not success:
            raise HTTPException(status_code=404, detail="无法撤销该优化")
        
        return {"success": True, "message": "优化已撤销"}
    
    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"Failed to undo optimization: {str(e)}")
        raise HTTPException(status_code=500, detail=f"撤销失败: {str(e)}")


@router.get("/{task_id}/export")
async def export_analysis(
    task_id: str,
    current_user: User = Depends(get_current_user)
):
    """
    导出分析结果
    
    导出完整的分析报告
    """
    try:
        export_data = optimization_engine.export_analysis(task_id)
        
        if not export_data:
            raise HTTPException(status_code=404, detail="任务不存在")
        
        return JSONResponse(content=export_data)
    
    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"Failed to export analysis: {str(e)}")
        raise HTTPException(status_code=500, detail=f"导出失败: {str(e)}")


@router.websocket("/ws/{task_id}")
async def websocket_endpoint(websocket: WebSocket, task_id: str):
    """
    WebSocket连接端点
    
    实时推送分析进度和结果
    """
    await manager.connect(websocket, task_id)
    
    try:
        while True:
            # 接收消息
            data = await websocket.receive_text()
            message = json.loads(data)
            
            if message.get("type") == "ping":
                await manager.send_message(
                    json.dumps({"type": "pong"}),
                    task_id
                )
            
            elif message.get("type") == "get_progress":
                # 获取分析进度
                analysis = optimization_engine.analysis_cache.get(task_id)
                if analysis:
                    progress_data = {
                        "type": "progress",
                        "status": analysis.status.value,
                        "overall_score": analysis.overall_score,
                        "suggestions_count": len(analysis.all_suggestions)
                    }
                    await manager.send_message(
                        json.dumps(progress_data),
                        task_id
                    )
    
    except WebSocketDisconnect:
        manager.disconnect(task_id)
        logger.info(f"WebSocket disconnected: {task_id}")
    except Exception as e:
        logger.error(f"WebSocket error: {str(e)}")
        manager.disconnect(task_id)


@router.get("/health")
async def health_check():
    """
    健康检查
    
    检查优化服务是否正常运行
    """
    return {
        "status": "healthy",
        "service": "optimization",
        "timestamp": datetime.now().isoformat(),
        "cache_size": len(optimization_engine.analysis_cache)
    }